package com.winsdom.service.impl;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.winsdom.config.SmsTemplateProperties;
import com.winsdom.domain.dto.collection.NotificationDefaultConfigDTO;
import com.winsdom.dto.sms.SmsTemplateDTO;
import com.winsdom.entity.Customer;
import com.winsdom.entity.CustomerNotificationConfig;
import com.winsdom.mapper.SmsTemplateMapper;
import com.winsdom.service.CollectionService;
import com.winsdom.service.SmsTemplateService;
import com.winsdom.utils.SmsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.mail.internet.MimeMessage;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: 陈文平
 * @CreateTime: 2025-05-11-18:45
 * @Description:
 * @Version: 1.0
 */
@Slf4j
@Service
public class SmsTemplateServiceImpl  implements SmsTemplateService {

    @Autowired
    private SmsTemplateProperties notificationProperties;

    @Autowired
    private JavaMailSender mailSender;         // Spring 邮件发送器



    @Autowired
    private SmsTemplateMapper smsTemplateMapper;

    @Autowired
    private CollectionService collectionService;


    /**
     * 返回所有模板
     * @return
     */
    @Override
    public List<Map<String, Object>> getAllSmsTemplates() {
        // 从Map<String, TemplateConfig>获取模板
        Map<String, SmsTemplateProperties.TemplateConfig> originalTemplates = notificationProperties.getSmsTemplates();
        List<Map<String, Object>> resultList = new ArrayList<>();

        for (Map.Entry<String, SmsTemplateProperties.TemplateConfig> entry : originalTemplates.entrySet()) {
            String templateKey = entry.getKey();
            SmsTemplateProperties.TemplateConfig config = entry.getValue();

            // 处理模板信息中的占位符
            String processedContent = config.getTemplateInfo()
                    .replace("{【", "【")
                    .replace("】}", "】");

            // 封装结果时增加templateName和serviceNode
            Map<String, Object> item = new HashMap<>();
            item.put("templateKey", templateKey);
            item.put("templateName", config.getTemplateName());    //模板名称
            item.put("serviceNode", config.getServiceNode());      //业务节点
            item.put("templateInfo", processedContent);            //模板信息
            resultList.add(item);
        }
        return resultList;
    }

    /**
     * 返回填充后的单个模板（按 templateKey 过滤）
     * @param templateKey 模板键
     * @param params 填充参数
     * @return
     */
    @Override
    public Map<String, Object> getSmsTemplateInfo(String templateKey, Map<String, String> params) {
        // 1. 检查模板是否存在
        Map<String, SmsTemplateProperties.TemplateConfig> allTemplates = notificationProperties.getSmsTemplates();
        if (CollectionUtils.isEmpty(allTemplates)) {
            throw new IllegalArgumentException("无可用模板");
        }
        SmsTemplateProperties.TemplateConfig config = allTemplates.get(templateKey);
        if (config == null) {
            throw new IllegalArgumentException("此模板不存在，key=" + templateKey);
        }

        // 2. 提取模板中的所有占位符（包括公司公众号名称）
        List<String> allParamsInTemplate = extractRequiredParams(config.getTemplateInfo());

        // 3. 自动填充"公司公众号名称"为配置值
        String companyWechatName = notificationProperties.getCompanyWechatName();
        if (companyWechatName == null || companyWechatName.isEmpty()) {
            throw new IllegalArgumentException("配置错误：未设置公司公众号名称");
        }
        params.put("公司公众号名称", companyWechatName);  // 自动添加到参数中

        // 4. 校验参数完整性（仅校验除"公司公众号名称"外的其他必填参数）
        List<String> requiredParams = new ArrayList<>(allParamsInTemplate);
        requiredParams.remove("公司公众号名称");  // 移除无需前端传入的参数
        validateParams(requiredParams, params);

        // 5. 填充模板
        String filledTemplate = SmsUtil.processTemplate(params, config.getTemplateInfo());

        // 6. 封装结果
        Map<String, Object> result = new HashMap<>();
        result.put("templateKey", templateKey);
        result.put("templateName", config.getTemplateName());
        result.put("serviceNode", config.getServiceNode());
        result.put("templateInfo", filledTemplate);
        return result;
    }

    /**
     * 提取模板中的必填参数
     * @param template 模板内容
     * @return 参数列表
     */
    private List<String> extractRequiredParams(String template) {
        List<String> requiredParams = new ArrayList<>();
        Pattern pattern = Pattern.compile("\\{【(.*?)】\\}");
        Matcher matcher = pattern.matcher(template);
        while (matcher.find()) {
            requiredParams.add(matcher.group(1)); // 直接使用group(1)提取参数名
        }
        return requiredParams;
    }

    /**
     * 校验参数完整性
     * @param requiredParams 必填参数列表
     * @param params 实际请求参数
     */
    private void validateParams(List<String> requiredParams, Map<String, String> params) {
        for (String param : requiredParams) {
            if (!params.containsKey(param)) {
                throw new IllegalArgumentException("缺少必填参数：" + param);
            }
        }
    }

    /**
     * 邮件发送实现
     * @param toEmail 收件人邮箱
     * @param templateKey 模板键
     * @param params 模板填充参数
     */
    @Override
    public void sendTemplateByEmail(String toEmail, String templateKey, Map<String, String> params) {
        // 1. 校验邮箱格式
        if (!toEmail.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
            throw new IllegalArgumentException("收件人邮箱格式错误");
        }

        // 2. 复用原有接口获取填充后的模板
        Map<String, Object> filledTemplate = getSmsTemplateInfo(templateKey, params);
        String content = (String) filledTemplate.get("templateInfo");

        // 3. 构造邮件内容
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            NotificationDefaultConfigDTO config = collectionService.getDefaultConfig();
            String billNotificationRemark = config.getBillNotificationRemark();
            helper.setFrom(notificationProperties.getMailFrom());
            helper.setTo(toEmail);
            helper.setSubject("【物业信息】" + filledTemplate.get("templateName"));
            helper.setText("<h3>智慧物业服务</h3><p>" + content + billNotificationRemark +"</p>", true);

            mailSender.send(message);
        } catch (Exception e) {
            // 添加日志记录，方便排查问题
            System.err.println("邮件发送失败: " + e.getMessage());
            throw new RuntimeException("邮件发送失败：" + e.getMessage());
        }
    }


    /**
     * 发送电子发票通知
     * @param customerId
     */
    @Override
    public void sendInvoicingNotification(Long customerId) {
        // 1. 查询缴费信息（包含客户名称、手机号、邮箱）
        Map<String, Object> paymentInfo = getPaymentInfoByCustomerId(customerId);
        String customerName = (String) paymentInfo.get("customerName");
        String mobilePhone = (String) paymentInfo.get("mobilePhone");
        String email = (String) paymentInfo.get("email");

        // 2. 参数校验
        if (!StringUtils.hasText(customerName)) {
            throw new IllegalArgumentException("客户名称未维护");
        }

        // 3. 组装模板参数
        Map<String, String> params = new HashMap<>();
        params.put("客户名称", customerName);

        // 4. 发送短信和邮件
        if (StringUtils.hasText(mobilePhone)) {
            sendTemplateByPhone(mobilePhone, "invoicing", params);
        }
        if (StringUtils.hasText(email)) {
            sendTemplateByEmail(email, "invoicing", params);
        }
    }



    /**
     * 发送账单通知（通过账单编号）
     * @param billNo 账单编号
     */
    @Override
    public void sendBillNotification(String billNo) {
        // 1. 根据账单编号查询具体缴费记录
        SmsTemplateDTO paymentRecord = smsTemplateMapper.selectPaymentRecordByBillNo(billNo);
        if (paymentRecord == null) {
            throw new IllegalArgumentException("未找到该账单编号的未付记录");
        }

        // 2. 从缴费记录中提取当前账单的关键信息
        Long customerId = paymentRecord.getCustomer().getCustomerId();
        String customerName = paymentRecord.getCustomer().getCustomerName();
        String billingCycle = paymentRecord.getBillingMain().getBillingPeriod();
        BigDecimal owedAmount = paymentRecord.getBills().getArrearsAmount();

        // 3. 通过客户ID查询通知配置
        Map<String, Object> paymentInfo = getPaymentInfoByCustomerId(customerId);

        // 4. 校验通知开关（payment_notify_enabled=1才允许发送）
        Boolean paymentNotifyEnabled = (Boolean) paymentInfo.get("paymentNotifyEnabled");
        if (paymentNotifyEnabled == null || !paymentNotifyEnabled) {
            log.warn("该客户未启用账单通知");
            throw new IllegalArgumentException("该客户未启用账单通知");
        }

        // 5. 基础参数校验（直接使用当前账单的信息）
        if (!StringUtils.hasText(customerName)) {
            throw new IllegalArgumentException("客户名称未维护");
        }
        if (!StringUtils.hasText(billingCycle)) {
            throw new IllegalArgumentException("账期未维护");
        }
        if (owedAmount == null || owedAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("无有效欠款金额");
        }


        // 6. 组装模板参数（使用当前账单的账期和金额）
        Map<String, String> params = new HashMap<>();
        params.put("客户名称", customerName);
        params.put("账期", billingCycle);
        params.put("账单金额", owedAmount.toPlainString());
//        params.put("billNotificationRemark", billNotificationRemark);

        // 7. 获取客户联系方式（从通知配置中获取）
        Integer paymentNotifyType = (Integer) paymentInfo.get("paymentNotifyType");
        String mobilePhone = (String) paymentInfo.get("mobilePhone");
        String email = (String) paymentInfo.get("email");

        // 8. 根据通知方式发送（原有逻辑）
        if ((paymentNotifyType == 0 || paymentNotifyType == 2) && StringUtils.hasText(mobilePhone)) {
            sendTemplateByPhone(mobilePhone, "billNotification", params);
        }
        if ((paymentNotifyType == 1 || paymentNotifyType == 2) && StringUtils.hasText(email)) {
            sendTemplateByEmail(email, "billNotification", params);
        }
    }

    /**
     * 发送催收通知（修改后：每个未付账单单独发送）
     * @param customerId 客户ID
     */
    @Override
    @Transactional // 声明事务：发送通知和更新次数必须同时成功/失败
    public void sendCollectReminder(Long customerId) {
        // 1. 查询客户所有未付缴费记录（包含通知配置和客户信息）
        List<SmsTemplateDTO> unpaidRecords = smsTemplateMapper.selectPaymentInfoByCustomerId(customerId);
        if (CollectionUtils.isEmpty(unpaidRecords)) {
            throw new IllegalArgumentException("未找到该客户的未付缴费记录");
        }

        // 提取客户级别的通知配置（所有记录的配置相同，取第一条）
        SmsTemplateDTO firstRecord = unpaidRecords.get(0);
        CustomerNotificationConfig config = firstRecord.getCustomerNotificationConfig();
        Customer customer = firstRecord.getCustomer();

        // 2. 校验通知开关（collection_notify_enabled=1才允许发送）
        if (!config.getCollectionNotifyEnabled()) {
            log.warn("该客户未启用催收通知");
            throw new IllegalArgumentException("该客户未启用催收通知");
        }

        // 3. 校验当前次数是否超过最大限制
        Integer currentNoticeTimes = config.getCurrentNoticeTimes();
        Integer maxNoticeTimes = config.getMaxNoticeTimes();
        if (currentNoticeTimes == null || maxNoticeTimes == null) {
            log.warn("客户催收通知次数配置异常");
            throw new IllegalArgumentException("客户催收通知次数配置异常");
        }
        if (currentNoticeTimes >= maxNoticeTimes) {
            log.warn("已达到最大催收通知次数");
            throw new IllegalArgumentException("已达到最大催收通知次数（" + maxNoticeTimes + "次），无法发送");
        }

        // 4. 遍历每个未付账单，单独发送通知
        for (SmsTemplateDTO record : unpaidRecords) {
            // 基础参数校验（单个账单）
            String customerName = customer.getCustomerName();
            BigDecimal owedAmount = record.getBills().getArrearsAmount();
            String billingCycle = record.getBillingMain().getBillingPeriod();
            if (!StringUtils.hasText(customerName)) {
                throw new IllegalArgumentException("客户名称未维护");
            }
            if (owedAmount == null || owedAmount.compareTo(BigDecimal.ZERO) <= 0) {
                throw new IllegalArgumentException("账单[" + record.getBills().getBillNumber() + "]无有效欠款金额");
            }

            // 5. 组装单个账单的模板参数（使用当前账单的具体信息）
            Map<String, String> params = new HashMap<>();
            params.put("客户名称", customerName);
            params.put("应收金额", owedAmount.toPlainString());
            params.put("账期", billingCycle);

            // 6. 根据通知方式发送（短信/邮件）
            Integer collectionNotifyType = config.getCollectionNotifyType();
            String mobilePhone = customer.getMobilePhone();
            String email = customer.getEmail();

            // 短信发送（type=0或2时）
            if ((collectionNotifyType == 0 || collectionNotifyType == 2) && StringUtils.hasText(mobilePhone)) {
                sendTemplateByPhone(mobilePhone, "collectReminder", params);
            }
            // 邮件发送（type=1或2时）
            if ((collectionNotifyType == 1 || collectionNotifyType == 2) && StringUtils.hasText(email)) {
                sendTemplateByEmail(email, "collectReminder", params);
            }
        }

        // 7. 所有账单发送成功后，更新客户通知次数（+1）
        updateCollectionNoticeTimesAndDate(customerId);
    }

    /**
     *发送电子收据通知
     * @param customerId
     */
    @Override
    public void sendIssurReceiptNotification(Long customerId) {
        // 1. 查询缴费信息（客户名称）
        Map<String, Object> paymentInfo = getPaymentInfoByCustomerId(customerId);
        String customerName = (String) paymentInfo.get("customerName");
        String mobilePhone = (String) paymentInfo.get("mobilePhone");
        String email = (String) paymentInfo.get("email");
        if (!StringUtils.hasText(customerName)) {
            throw new IllegalArgumentException("此客户不存在");
        }

        // 3. 组装模板参数
        Map<String, String> params = new HashMap<>();
        params.put("客户名称", customerName);

        // 4. 发送短信和邮件
        if (StringUtils.hasText(mobilePhone)) {
            sendTemplateByPhone(mobilePhone, "issurReceipt", params);
        }
        if (StringUtils.hasText(email)) {
            sendTemplateByEmail(email, "issurReceipt", params);
        }
    }


    /**
     * 根据多个客户ID,一次性发送多个催收通知
     * @param customerIds 客户ID列表
     */
    @Override
    public Map<String, Object> sendCollectReminderMultiple(List<Long> customerIds) {
        List<Long> successIds = new ArrayList<>();
        List<Map<String, String>> failIds = new ArrayList<>(); // 记录失败的客户ID和原因

        for (Long customerId : customerIds) {
            try {
                // 调用单个催收通知逻辑
                sendCollectReminder(customerId);
                successIds.add(customerId);
            } catch (Exception e) {
                // 记录失败原因（提取异常信息）
                Map<String, String> failItem = new HashMap<>();
                failItem.put("customerId", String.valueOf(customerId));
                failItem.put("reason", e.getMessage());
                failIds.add(failItem);
                log.error("客户ID={} 催收通知发送失败：{}", customerId, e.getMessage());
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("successIds", successIds);
        result.put("failIds", failIds);
        return result;
    }

    /**
     * 根据多个客户ID,一次性发送多个账单通知
     * @param billNos 客户ID列表
     */
    @Override
    public Map<String, Object> sendBillNotificationMultiple(List<String> billNos) {
        List<String> successIds = new ArrayList<>();
        List<Map<String, String>> failIds = new ArrayList<>(); // 记录失败的账单编号和原因

        for (String billNo : billNos) {
            try {
                // 调用单个账单通知逻辑
                sendBillNotification(billNo);
                successIds.add(billNo);
            } catch (Exception e) {
                // 记录失败原因（提取异常信息）
                Map<String, String> failItem = new HashMap<>();
                failItem.put("billNo", billNo);
                failItem.put("reason", e.getMessage());
                failIds.add(failItem);
                log.error("账单编号={} 发送失败：{}", billNo, e.getMessage());
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("successIds", successIds);
        result.put("failIds", failIds);
        return result;
    }


    /**
     * 发送短信的通用方法
     * @param phone
     * @param templateKey
     * @param params
     */
    @Override
    public void sendTemplateByPhone(String phone, String templateKey, Map<String, String> params) {
        // 1. 校验手机号码格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new IllegalArgumentException("手机号码格式错误");
        }
//
//        // 2. 复用原有接口获取填充后的模板
        Map<String, Object> filledTemplate = getSmsTemplateInfo(templateKey, params);
        String content = (String) filledTemplate.get("templateInfo");

        // 3. 构造短信请求
        DefaultProfile profile = DefaultProfile.getProfile("default", "LTAI5tCZ8Sbed4WeGVbDsqJv", "f0dT6xtqpvOKDIUAQLh32sdwutelo9");
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
//        request.setProtocol(com.aliyuncs.http.ProtocolType.HTTPS);
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");

        request.putQueryParameter("PhoneNumbers", phone);
        request.putQueryParameter("SignName", "阿里云短信测试");
        request.putQueryParameter("TemplateCode", "SMS_154950909");
        String templateInfo = notificationProperties.getSmsTemplates().get(templateKey).getTemplateInfo();
//        String jsonParams = SmsUtil.processTemplateToJson(params, templateInfo); // 生成JSON参数
//        request.putQueryParameter("TemplateParam", jsonParams);
        request.putQueryParameter("TemplateParam", SmsUtil.processTemplate(params, notificationProperties.getSmsTemplates().get(templateKey).getTemplateInfo()));


        try {
            // 4. 发送短信
            CommonResponse response = client.getCommonResponse(request);
            if (!response.getHttpResponse().isSuccess()) {
                // 添加日志记录，方便排查问题
                System.err.println("短信发送失败: " + response.getData());
                throw new RuntimeException("短信发送失败：" + response.getData());
            }
        } catch (Exception e) {
            // 添加日志记录，方便排查问题
            System.err.println("短信发送异常: " + e.getMessage());
            throw new RuntimeException("短信发送异常", e);
        }
    }


    /**
     * 根据客户ID获取未付缴费记录信息
     * @param customerId
     * @return
     */
    @Override
    public Map<String, Object> getPaymentInfoByCustomerId(Long customerId) {
        Assert.notNull(customerId, "客户ID不能为空");

        // 查询所有未付记录（连表获取联系方式和通知配置）
        List<SmsTemplateDTO> unpaidRecords = smsTemplateMapper.selectPaymentInfoByCustomerId(customerId);
        if (CollectionUtils.isEmpty(unpaidRecords)) {
            throw new IllegalArgumentException("未找到该客户的未付缴费记录");
        }

        // 汇总账期、总欠款金额，并提取通知配置（所有记录的配置相同，取第一条）
        List<String> billingCycles = new ArrayList<>();
        BigDecimal totalOwedAmount = BigDecimal.ZERO;
        SmsTemplateDTO firstRecord = unpaidRecords.get(0);  // 第一条记录包含配置信息

        for (SmsTemplateDTO record : unpaidRecords) {
            // 收集唯一账期
            String billingCycle = record.getBillingMain().getBillingPeriod();
            if (StringUtils.hasText(billingCycle) && !billingCycles.contains(billingCycle)) {
                billingCycles.add(billingCycle);
            }
            // 累加欠款金额
            BigDecimal owedAmount = record.getBills().getArrearsAmount();
            if (owedAmount != null) {
                totalOwedAmount = totalOwedAmount.add(owedAmount);
            }
        }

        Customer customer = firstRecord.getCustomer();
        CustomerNotificationConfig config = firstRecord.getCustomerNotificationConfig();

        // 封装结果（包含通知配置字段）
        Map<String, Object> result = new HashMap<>();
        result.put("customerName", customer.getCustomerName());
        result.put("billingCycles", billingCycles);  // 账期集合
        result.put("totalOwedAmount", totalOwedAmount);  // 总欠款金额
        result.put("mobilePhone", customer.getMobilePhone());
        result.put("email", customer.getEmail());
        result.put("paymentNotifyEnabled", config.getPaymentNotifyEnabled());  // 缴款通知开关
        result.put("paymentNotifyType", config.getPaymentNotifyType());        // 缴款通知方式
        result.put("collectionNotifyEnabled", config.getCollectionNotifyEnabled());  // 催收通知开关
        result.put("collectionNotifyType", config.getCollectionNotifyType());        // 催收通知方式
        result.put("currentNoticeTimes", config.getCurrentNoticeTimes());
        result.put("maxNoticeTimes", config.getMaxNoticeTimes());
        return result;
    }

    /**
     * 修改催缴次数以及更新时间
     * @param customerId 客户ID
     */
    @Override
    public void updateCollectionNoticeTimesAndDate(Long customerId) {
        Assert.notNull(customerId, "客户ID不能为空");
        smsTemplateMapper.updateCollectionNoticeTimesAndDate(customerId);
    }



}